package com.sample.generator.template.impl;

import java.io.IOException;
import java.io.Writer;
import java.util.Map;
import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;

import com.sample.generator.GenerationFailureException;
import com.sample.generator.config.TemplateConfig;
import com.sample.generator.config.WriterConfig;

public class VelocityTemplateProcessor extends AbstractTemplateProcessor {

	private VelocityEngine engine = new VelocityEngine();

	@Override
	public void setTemplateConfig(TemplateConfig templateConfig)
			throws GenerationFailureException {

		super.setTemplateConfig(templateConfig);
		initVelocityEngine(templateConfig);
	}

	public void process(Map<String, Object> contextMap,
			WriterConfig writerConfig) throws GenerationFailureException {

		TemplateConfig templateConfig = getTemplateConfig();
		Template template = getVelocityTemplate(templateConfig);
		VelocityContext context = getVelocityContext(contextMap, writerConfig);
		merge(template, context, writerConfig);
	}

	protected VelocityEngine getVelocityEngine() {

		return engine;
	}

	protected void initVelocityEngine(TemplateConfig config) {

		Properties props = getInitProperties(config);
		try {
			getVelocityEngine().init(props);
		} catch (Exception e) {
			throw new GenerationFailureException(e);
		}
	}

	protected Template getVelocityTemplate(TemplateConfig templateConfig) {

		String name = templateConfig.getName();
		String encoding = templateConfig.getEncoding();
		try {
			Template template = getVelocityEngine().getTemplate(name, encoding);
			return template;
		} catch (ResourceNotFoundException e) {
			throw new GenerationFailureException(e);
		} catch (ParseErrorException e) {
			throw new GenerationFailureException(e);
		} catch (Exception e) {
			throw new GenerationFailureException(e);
		}
	}

	protected VelocityContext getVelocityContext(
			Map<String, Object> contextMap, WriterConfig config) {

		VelocityContext context = new VelocityContext(contextMap);
		return new VelocityContext(config.getContextAttributeMap(), context);
	}

	protected void merge(Template template, VelocityContext context,
			WriterConfig config) {

		Writer writer = null;
		try {
			writer = config.getWriter();
			template.merge(context, writer);
			writer.flush();
		} catch (IOException e) {
			throw new GenerationFailureException(e);
		} finally {
			if (writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					throw new GenerationFailureException(e);
				}
			}
		}
	}
}
